﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.IO;
using System.Text;
using System.ComponentModel;
using System.Windows.Media.Imaging;
using System.Threading;
using System.Security.Cryptography;
using System.Windows.Threading;
using System.Windows;
using BrainTechLLC;
using BrainTechLLC.ThreadSafeObjects;
using AForge;
using AForge.Imaging;
using AForge.Imaging.Filters;
using System.Collections.ObjectModel;
using System.Windows.Media;

namespace WpfImageDuplicates
{
    public class OriginalAndTransformedBitmap : FileImage, INotifyPropertyChanged
    {
        protected Bitmap _transformedBitmap;
        internal bool _transformedDirty;
        protected FilterCollection _filterCollection;                        
        protected object _lockObj = new object();

        public OriginalAndTransformedBitmap()
            : base()
        {
        }

        public OriginalAndTransformedBitmap(IFileImage fileImage)
            : this()
        {
            fileImage.CopyTo(this);
        }

        public OriginalAndTransformedBitmap(IFileImage fileImage, FilterCollection filters)
            : this(filters)
        {
            fileImage.CopyTo(this);
        }

        public OriginalAndTransformedBitmap(FilterCollection filters)
            : this()
        {
            _filterCollection = filters;
            _filterCollection.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(_filterCollection_CollectionChanged);
        }

        void _filterCollection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            MarkDirty(Settings.Values.WantFilterThumbnails);
        }               

        public override Bitmap BitmapCached
        {
            get { return _bitmap; }
        }

        public override BitmapImage BitmapImage
        {
            get
            {
                if (this._bitmapImage == null)
                {
                    lock (_lockObj)
                    {
                        if (this._bitmapImage == null && _bitmap != null)
                        {
                            MemoryStream ms = new MemoryStream();
                            _bitmap.Save(ms, ImageFormat.Bmp);
                            var temp = new BitmapImage();
                            temp.BeginInit();
                            temp.StreamSource = ms;
                            temp.EndInit();
                            BitmapImage = temp;
                        }
                    }
                }
                return this._bitmapImage;
            }
            set
            {
                if (this._bitmapImage != value)
                {
                    _bitmapImage = value;
                    OnPropertyChanged("BitmapImage");
                }
            }
        }

        public override Bitmap Bitmap
        {
            get
            {
                return _bitmap;
            }
            set
            {
                if (_bitmap != value)
                {
                    _bitmap = value;
                    MarkDirty(false);
                    OnPropertyChanged("Bitmap");
                }
            }
        }

        public FilterCollection FilterCollection
        {
            get
            {
                return _filterCollection;
            }
            set
            {
                if (_filterCollection != value)
                {
                    _filterCollection = value;
                    MarkDirty(false);
                    OnPropertyChanged("FilterCollection");
                }
            }
        }

        public Bitmap TransformedBitmapCached
        {
            get
            {
                if (_transformedDirty)
                {
                    return null;
                }

                return _transformedBitmap;
            }
        }

        public Bitmap TransformedBitmap
        {
            get
            {
                if ((_transformedDirty || _transformedBitmap == null) && _bitmap != null)
                {
                    Locked(() =>
                    {
                        TransformedBitmap = (_filterCollection == null) ? _bitmap : ApplyFilters(_bitmap, _filterCollection);
                        ImageSource = null;
                        _transformedDirty = false;
                    },
                        () => (_transformedDirty || _transformedBitmap == null) && _bitmap != null);
                }

                return _transformedBitmap;
            }
            set
            {
                if (_transformedBitmap != value)
                {
                    _transformedBitmap = value;
                    OnPropertyChanged("TransformedBitmap");
                }
            }
        }

        public override ImageSource ImageSourceCached
        {
            get { return _imageSource; }
        }

        public override ImageSource ImageSource
        {
            get
            {
                if (_imageSource == null)
                {
                    Locked(() => ImageSource = TransformedBitmap.CreateImageSourceFromBitmap(), () => _imageSource == null);
                }

                return _imageSource;
            }
            set
            {
                if (_imageSource != value)
                {
                    _imageSource = value;
                    OnPropertyChanged("ImageSource");
                }
            }
        }        
        
        public override void MarkDirty(bool clearThumb)
        {
            TransformedBitmap = null;
            ImageSource = null;
            _transformedDirty = true;

            if (clearThumb)
            {
                Thumbnail = null;         
            }
        }        
        
        public Bitmap ApplyFilters(Bitmap originalBitmap, FilterCollection filters)
        {
            if (originalBitmap == null)
                return null;

            return filters.ApplyFilters(originalBitmap);
        }

        public Bitmap ApplyFilters(FilterCollection filters)
        {
            Bitmap originalBitmap = _bitmap;

            if (originalBitmap == null)
                return null;

            return filters.ApplyFilters(originalBitmap);
        }
    }
}
